Python

  • 自学 Python 第十一天
  • 学习Deep Dream
  • 本文参考了该网址
In [1]:
import tensorflow as tf
import numpy as np
import IPython.display as display 
import PIL.Image
from tensorflow.keras.preprocessing import image
In [2]:
tf.__version__
Out[2]:
'2.1.0'
In [3]:
## 图像标准化
def normalize_image(img):
    img = 255*(img+1.0)/2.0
    return tf.cast(img,tf.uint8)
In [4]:
## 图像可视化
def show_image(img):
    display.display(PIL.Image.fromarray(np.array(img)))
In [5]:
##保存图片
def save_image(img,file_name):
    PIL.Image.fromarray(np.array(img)).save(file_name)
In [6]:
##定义噪声图片
img_noise = np.random.uniform(size=(300,300,3))+100.##300X300的三通道图片
img_noise = img_noise.astype(np.float32)
show_image(normalize_image(img_noise))
In [7]:
##构建模型,tf.keras.applications包括许多预训练好的模型,我们用InceptionV3模型。去掉顶层,这样可以接受新的训练数据的shape
base_model = tf.keras.applications.InceptionV3(include_top=False,weights="imagenet")
Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5
87916544/87910968 [==============================] - 1417s 16us/step
In [18]:
#base_model.summary()
  • InceptionV3模型架构非常大,有"mixed0"到"mixed10"这样的11层.
  • 使用不同层会产生不同的图像, 较深的层对较高级的特征(比如眼睛和脸)有相应,较浅的层对较低级的特征(比边缘,形状和纹理)有相应。
  • 较深的层需要更长的时间训练,因为计算梯度更深入。

DeepDream主要想法是选择一个卷积层的某个通道或卷积层(也可以是多个网络层),改变图像像素,来最大化选中层或通道的激活值。下面是单层网络单通道

In [12]:
[InternetShortcut]
URL=http://localhost:8888/notebooks/DIYDay11_DeepDream.ipynb#DeepDream��Ҫ�뷨��ѡ��һ����������ij��ͨ���������㣨Ҳ�����Ƕ��������㣩���ı�ͼ�����أ���������ѡ�в���ͨ���ļ���ֵ��
[InternetShortcut.A]
URL=http://localhost:8888/notebooks/DIYDay11_DeepDream.ipynb#DeepDream��Ҫ�뷨��ѡ��һ����������ij��ͨ���������㣨Ҳ�����Ƕ��������㣩���ı�ͼ�����أ���������ѡ�в���ͨ���ļ���ֵ��
[InternetShortcut.W]
URL=http://localhost:8888/notebooks/DIYDay11+AF8-DeepDream.ipynb+ACM-DeepDream+TjuJgWDzbNVmL5AJYulOAE4qU3d571xCdoRn0E4qkBqQU2IWU3d571xC/whOX1PvTuVmL1kaTip/UX7cXEL/Cf8MZTlT2Fb+UM9Qz30g/wxnZWcAWSdTFpAJTi1cQmIWkBqQU3aEb8BtO1A8MAI-
layer_name="conv2d_85"
layers = base_model.get_layer(layer_name).output
In [13]:
layers
Out[13]:
<tf.Tensor 'conv2d_85/Identity:0' shape=(None, None, None, 320) dtype=float32>
In [15]:
##创建特征提取模型
dream_model = tf.keras.Model(inputs=base_model.input,outputs=layers)
In [17]:
#dream_model.summary()
In [19]:
##计算损失
def calc_loss(img,model):
    channel =13#不能超过320,因为<tf.Tensor 'conv2d_85/Identity:0' shape=(None, None, None, 320) dtype=float32>,最多320个通道
    #由(300,300,3)变为(1,300,300,3)
    img=tf.expand_dims(img,axis=0)
    layer_activations=model(img)
    act = layer_activations[:,:,:,channel]
    loss = tf.math.reduce_mean(act)##要使loss越来越大
    
    return loss  
In [24]:
## 图像优化过程
def render_deepdream(model,img,steps=100,step_size=0.01,verbose=1):
    for n in tf.range(steps):
        with tf.GradientTape() as tape:
            #对img进行梯度变换
            tape.watch(img)
            loss=calc_loss(img,model)
        #计算损失相对于输入图像的像素的梯度
        gradients = tape.gradient(loss,img)
        #归一化梯度值
        gradients /= tf.math.reduce_std(gradients)+1e-8
        #梯度上升,损失越大,所以是加,而不是减
        img=img+gradients*step_size
        img=tf.clip_by_value(img,-1,1)#让输出在-1,+1之间
        
        if(verbose ==1):
            if((n+1)%10==0):
                print("step {}/{},loss {}".format(n+1,steps,loss))
    return img
In [22]:
#图片预处理
img = tf.keras.applications.inception_v3.preprocess_input(img_noise)
img = tf.convert_to_tensor(img)
In [27]:
import time
star = time.time()
dream_img=render_deepdream(dream_model,img,steps=200)
print(time.time()-star)
step 10/200,loss 0.7232226133346558
step 20/200,loss 1.0906920433044434
step 30/200,loss 1.4964072704315186
step 40/200,loss 1.7863988876342773
step 50/200,loss 2.2643730640411377
step 60/200,loss 2.59293794631958
step 70/200,loss 2.886918783187866
step 80/200,loss 3.256265640258789
step 90/200,loss 3.42140531539917
step 100/200,loss 3.663994550704956
step 110/200,loss 3.7924013137817383
step 120/200,loss 3.9016551971435547
step 130/200,loss 4.060777187347412
step 140/200,loss 4.214878082275391
step 150/200,loss 4.291756629943848
step 160/200,loss 4.470706939697266
step 170/200,loss 4.504961967468262
step 180/200,loss 4.676396369934082
step 190/200,loss 4.800362586975098
step 200/200,loss 4.883273124694824
196.04741525650024
In [28]:
dream_img = normalize_image(dream_img)
show_image(dream_img)

单层网络多通道

In [1]:
import tensorflow as tf
import numpy as np
import IPython.display as display 
import PIL.Image
from tensorflow.keras.preprocessing import image
In [2]:
## 图像标准化
def normalize_image(img):
    img = 255*(img+1.0)/2.0
    return tf.cast(img,tf.uint8)
In [3]:
## 图像可视化
def show_image(img):
    display.display(PIL.Image.fromarray(np.array(img)))
In [4]:
##保存图片
def save_image(img,file_name):
    PIL.Image.fromarray(np.array(img)).save(file_name)
In [5]:
##定义噪声图片
img_noise = np.random.uniform(size=(300,300,3))+100.##300X300的三通道图片
img_noise = img_noise.astype(np.float32)
show_image(normalize_image(img_noise))
In [6]:
##构建模型,tf.keras.applications包括许多预训练好的模型,我们用InceptionV3模型。去掉顶层,这样可以接受新的训练数据的shape
base_model = tf.keras.applications.InceptionV3(include_top=False,weights="imagenet")
In [7]:
layer_name="conv2d_85"
layers = base_model.get_layer(layer_name).output
In [8]:
dream_model = tf.keras.Model(inputs=base_model.input,outputs=layers)
In [9]:
##计算损失,与单个通道相差就在于计算loss.
def calc_loss(img,model):
    channel =[13,19]#不能超过320,因为<tf.Tensor 'conv2d_85/Identity:0' shape=(None, None, None, 320) dtype=float32>,最多320个通道
    #由(300,300,3)变为(1,300,300,3)
    img=tf.expand_dims(img,axis=0)
    layer_activations=model(img)
    
    losses=[]
    for cn in channel:
        act = layer_activations[:,:,:,cn]
        loss = tf.math.reduce_mean(act)##要使loss越来越大
        losses.append(loss)
    
    
    return tf.reduce_sum(losses)  
In [10]:
## 图像优化过程
def render_deepdream(model,img,steps=100,step_size=0.01,verbose=1):
    for n in tf.range(steps):
        with tf.GradientTape() as tape:
            #对img进行梯度变换
            tape.watch(img)
            loss=calc_loss(img,model)
        #计算损失相对于输入图像的像素的梯度
        gradients = tape.gradient(loss,img)
        #归一化梯度值
        gradients /= tf.math.reduce_std(gradients)+1e-8
        #梯度上升,损失越大,所以是加,而不是减
        img=img+gradients*step_size
        img=tf.clip_by_value(img,-1,1)#让输出在-1,+1之间
        
        if(verbose ==1):
            if((n+1)%10==0):
                print("step {}/{},loss {}".format(n+1,steps,loss))
    return img
In [11]:
#图片预处理
img = tf.keras.applications.inception_v3.preprocess_input(img_noise)
img = tf.convert_to_tensor(img)
In [12]:
import time
star = time.time()
dream_img=render_deepdream(dream_model,img,steps=200)
print(time.time()-star)
step 10/200,loss 0.9086489677429199
step 20/200,loss 1.6820852756500244
step 30/200,loss 2.2268118858337402
step 40/200,loss 2.8536839485168457
step 50/200,loss 3.282090187072754
step 60/200,loss 3.529844284057617
step 70/200,loss 4.035492897033691
step 80/200,loss 4.399809837341309
step 90/200,loss 4.665487289428711
step 100/200,loss 4.618881702423096
step 110/200,loss 4.9446306228637695
step 120/200,loss 5.128018379211426
step 130/200,loss 5.355966567993164
step 140/200,loss 5.497516632080078
step 150/200,loss 5.611661434173584
step 160/200,loss 5.639852523803711
step 170/200,loss 5.860377311706543
step 180/200,loss 5.976480484008789
step 190/200,loss 6.083704948425293
step 200/200,loss 6.1605353355407715
197.5213828086853
In [14]:
show_image(normalize_image(dream_img))

多层网络全通道

In [1]:
import tensorflow as tf
import numpy as np
import IPython.display as display 
import PIL.Image
from tensorflow.keras.preprocessing import image
In [2]:
## 图像标准化
def normalize_image(img):
    img = 255*(img+1.0)/2.0
    return tf.cast(img,tf.uint8)
In [3]:
## 图像可视化
def show_image(img):
    display.display(PIL.Image.fromarray(np.array(img)))
In [4]:
##定义噪声图片
img_noise = np.random.uniform(size=(300,300,3))+100.##300X300的三通道图片
img_noise = img_noise.astype(np.float32)
show_image(normalize_image(img_noise))
In [5]:
##构建模型,tf.keras.applications包括许多预训练好的模型,我们用InceptionV3模型。去掉顶层,这样可以接受新的训练数据的shape
base_model = tf.keras.applications.InceptionV3(include_top=False,weights="imagenet")
In [6]:
#选择需要优化的层
layer_name=["mixed3","mixed5"]
layers = [base_model.get_layer(name).output for name in layer_name]
layers
Out[6]:
[<tf.Tensor 'mixed3/Identity:0' shape=(None, None, None, 768) dtype=float32>,
 <tf.Tensor 'mixed5/Identity:0' shape=(None, None, None, 768) dtype=float32>]
In [7]:
dream_model = tf.keras.Model(inputs=base_model.input,outputs=layers)
In [8]:
##计算损失,与单个通道相差就在于计算loss.
def calc_loss(img,model):
    #channel =[13,19]#不能超过320,因为<tf.Tensor 'conv2d_85/Identity:0' shape=(None, None, None, 320) dtype=float32>,最多320个通道
    #由(300,300,3)变为(1,300,300,3)
    #因为是全通道,所以不需要选择通道了
    img=tf.expand_dims(img,axis=0)
    layer_activations=model(img)
    
    losses=[]
    for act in layer_activations:
        loss = tf.math.reduce_mean(act)##要使loss越来越大
        losses.append(loss)
    
    
    return tf.reduce_sum(losses)  
In [9]:
## 图像优化过程
def render_deepdream(model,img,steps=100,step_size=0.01,verbose=1):
    for n in tf.range(steps):
        with tf.GradientTape() as tape:
            #对img进行梯度变换
            tape.watch(img)
            loss=calc_loss(img,model)
        #计算损失相对于输入图像的像素的梯度
        gradients = tape.gradient(loss,img)
        #归一化梯度值
        gradients /= tf.math.reduce_std(gradients)+1e-8
        #梯度上升,损失越大,所以是加,而不是减
        img=img+gradients*step_size
        img=tf.clip_by_value(img,-1,1)#让输出在-1,+1之间
        
        if(verbose ==1):
            if((n+1)%10==0):
                print("step {}/{},loss {}".format(n+1,steps,loss))
    return img
In [10]:
#图片预处理
img = tf.keras.applications.inception_v3.preprocess_input(img_noise)
img = tf.convert_to_tensor(img)
###
import time
star = time.time()
dream_img=render_deepdream(dream_model,img,steps=200)
print(time.time()-star)

show_image(normalize_image(dream_img))
step 10/200,loss 1.105385422706604
step 20/200,loss 1.4289933443069458
step 30/200,loss 1.633590579032898
step 40/200,loss 1.7945523262023926
step 50/200,loss 1.926966905593872
step 60/200,loss 2.0289182662963867
step 70/200,loss 2.1384453773498535
step 80/200,loss 2.223975658416748
step 90/200,loss 2.31330943107605
step 100/200,loss 2.382352352142334
step 110/200,loss 2.4504623413085938
step 120/200,loss 2.5235018730163574
step 130/200,loss 2.57602596282959
step 140/200,loss 2.6349873542785645
step 150/200,loss 2.6851940155029297
step 160/200,loss 2.7412304878234863
step 170/200,loss 2.783291816711426
step 180/200,loss 2.831172466278076
step 190/200,loss 2.8677217960357666
step 200/200,loss 2.9168996810913086
140.39057564735413

浅层到深层图越来越抽象

背景图像起点多层全通道,上面都是以噪音为起点

In [15]:
import tensorflow as tf
import numpy as np
import IPython.display as display 
import PIL.Image
from tensorflow.keras.preprocessing import image
In [16]:
##读取图片,可以设置图片的最大尺寸
def read_image(file_name,max_dim=None):
    img = PIL.Image.open(file_name)
    if max_dim:
        img.thumbnail((max_dim,max_dim))
    return np.array(img)
In [17]:
## 图像可视化
def show_image(img):
    display.display(PIL.Image.fromarray(np.array(img)))
In [18]:
original_img=read_image("IMG_20170713_091522.jpg",max_dim=500)
show_image(original_img)
In [19]:
## 图像标准化
def normalize_image(img):
    img = 255*(img+1.0)/2.0
    return tf.cast(img,tf.uint8)
In [20]:
##构建模型,tf.keras.applications包括许多预训练好的模型,我们用InceptionV3模型。去掉顶层,这样可以接受新的训练数据的shape
base_model = tf.keras.applications.InceptionV3(include_top=False,weights="imagenet")
In [21]:
#选择需要优化的层
layer_name=["mixed3","mixed5"]
layers = [base_model.get_layer(name).output for name in layer_name]
layers
Out[21]:
[<tf.Tensor 'mixed3_1/Identity:0' shape=(None, None, None, 768) dtype=float32>,
 <tf.Tensor 'mixed5_1/Identity:0' shape=(None, None, None, 768) dtype=float32>]
In [22]:
dream_model = tf.keras.Model(inputs=base_model.input,outputs=layers)
In [23]:
##计算损失,与单个通道相差就在于计算loss.
def calc_loss(img,model):
    #channel =[13,19]#不能超过320,因为<tf.Tensor 'conv2d_85/Identity:0' shape=(None, None, None, 320) dtype=float32>,最多320个通道
    #由(300,300,3)变为(1,300,300,3)
    #因为是全通道,所以不需要选择通道了
    img=tf.expand_dims(img,axis=0)
    layer_activations=model(img)
    
    losses=[]
    for act in layer_activations:
        loss = tf.math.reduce_mean(act)##要使loss越来越大
        losses.append(loss)
    
    
    return tf.reduce_sum(losses)  
In [24]:
## 图像优化过程
def render_deepdream(model,img,steps=100,step_size=0.01,verbose=1):
    for n in tf.range(steps):
        with tf.GradientTape() as tape:
            #对img进行梯度变换
            tape.watch(img)
            loss=calc_loss(img,model)
        #计算损失相对于输入图像的像素的梯度
        gradients = tape.gradient(loss,img)
        #归一化梯度值
        gradients /= tf.math.reduce_std(gradients)+1e-8
        #梯度上升,损失越大,所以是加,而不是减
        img=img+gradients*step_size
        img=tf.clip_by_value(img,-1,1)#让输出在-1,+1之间
        
        if(verbose ==1):
            if((n+1)%10==0):
                print("step {}/{},loss {}".format(n+1,steps,loss))
    return img
In [25]:
#图片预处理
img = tf.keras.applications.inception_v3.preprocess_input(original_img)
img = tf.convert_to_tensor(img)
###
import time
star = time.time()
dream_img=render_deepdream(dream_model,img,steps=200)
print(time.time()-star)
step 10/200,loss 1.1958743333816528
step 20/200,loss 1.5008963346481323
step 30/200,loss 1.6872920989990234
step 40/200,loss 1.8209846019744873
step 50/200,loss 1.9249705076217651
step 60/200,loss 2.0126936435699463
step 70/200,loss 2.0882534980773926
step 80/200,loss 2.1542584896087646
step 90/200,loss 2.2138986587524414
step 100/200,loss 2.2683467864990234
step 110/200,loss 2.318314790725708
step 120/200,loss 2.3648135662078857
step 130/200,loss 2.407626152038574
step 140/200,loss 2.4486749172210693
step 150/200,loss 2.4879021644592285
step 160/200,loss 2.5248899459838867
step 170/200,loss 2.5600898265838623
step 180/200,loss 2.5943689346313477
step 190/200,loss 2.6271708011627197
step 200/200,loss 2.6585497856140137
260.2778289318085
In [27]:
show_image(normalize_image(dream_img))

上面生成的图片存在几个问题:

  • 输出有噪声
  • 图片分辨率低
  • 输出的特征模式都一样
  • 可以在不同比例图上使用梯度上升来解决这些问题,并在小比例图上生成的结果合并到更大比例的图上。

优化1(多层全通道)

In [1]:
import tensorflow as tf
import numpy as np
import IPython.display as display 
import PIL.Image
from tensorflow.keras.preprocessing import image
In [2]:
##读取图片,可以设置图片的最大尺寸
def read_image(file_name,max_dim=None):
    img = PIL.Image.open(file_name)
    if max_dim:
        img.thumbnail((max_dim,max_dim))
    return np.array(img)
In [3]:
## 图像可视化
def show_image(img):
    display.display(PIL.Image.fromarray(np.array(img)))
In [5]:
original_img=read_image("IMG_20170713_091522.jpg",max_dim=500)
In [6]:
## 图像标准化
def normalize_image(img):
    img = 255*(img+1.0)/2.0
    return tf.cast(img,tf.uint8)
In [7]:
##构建模型,tf.keras.applications包括许多预训练好的模型,我们用InceptionV3模型。去掉顶层,这样可以接受新的训练数据的shape
base_model = tf.keras.applications.InceptionV3(include_top=False,weights="imagenet")
In [8]:
#选择需要优化的层
layer_name=["mixed3","mixed5","mixed7"]
layers = [base_model.get_layer(name).output for name in layer_name]
In [9]:
dream_model = tf.keras.Model(inputs=base_model.input,outputs=layers)
In [10]:
##计算损失,与单个通道相差就在于计算loss.
def calc_loss(img,model):
    #channel =[13,19]#不能超过320,因为<tf.Tensor 'conv2d_85/Identity:0' shape=(None, None, None, 320) dtype=float32>,最多320个通道
    #由(300,300,3)变为(1,300,300,3)
    #因为是全通道,所以不需要选择通道了
    img=tf.expand_dims(img,axis=0)
    layer_activations=model(img)
    
    losses=[]
    for act in layer_activations:
        loss = tf.math.reduce_mean(act)##要使loss越来越大
        losses.append(loss)
    
    return tf.reduce_sum(losses)  
In [11]:
## 图像优化过程
def render_deepdream(model,img,steps=100,step_size=0.01,verbose=1):
    for n in tf.range(steps):
        with tf.GradientTape() as tape:
            #对img进行梯度变换
            tape.watch(img)
            loss=calc_loss(img,model)
        #计算损失相对于输入图像的像素的梯度
        gradients = tape.gradient(loss,img)
        #归一化梯度值
        gradients /= tf.math.reduce_std(gradients)+1e-8
        #梯度上升,损失越大,所以是加,而不是减
        img=img+gradients*step_size
        img=tf.clip_by_value(img,-1,1)#让输出在-1,+1之间
        
        if(verbose ==1):
            if((n+1)%10==0):
                print("step {}/{},loss {}".format(n+1,steps,loss))
    return img
In [12]:
import time
star = time.time()
#图片预处理
Scale=1.3
img = tf.keras.applications.inception_v3.preprocess_input(original_img)
img = tf.convert_to_tensor(img)
initial_shape=tf.shape(img)[:-1]
##从小到大比例进行多次优化过程
for each in range(-2,3):
    new_size=tf.cast(tf.convert_to_tensor(initial_shape),tf.float32)*(Scale**each)
    img=tf.image.resize(img,tf.cast(new_size,tf.int32))
    
    img=render_deepdream(dream_model,img)
    
img = tf.image.resize(img,initial_shape)

print(time.time()-star)
step 10/100,loss 1.3041775226593018
step 20/100,loss 1.579925775527954
step 30/100,loss 1.7464714050292969
step 40/100,loss 1.8638074398040771
step 50/100,loss 1.9594813585281372
step 60/100,loss 2.0303080081939697
step 70/100,loss 2.1056153774261475
step 80/100,loss 2.1634151935577393
step 90/100,loss 2.2233052253723145
step 100/100,loss 2.2769861221313477
step 10/100,loss 1.5858268737792969
step 20/100,loss 1.810757040977478
step 30/100,loss 1.9607442617416382
step 40/100,loss 2.0697343349456787
step 50/100,loss 2.1574018001556396
step 60/100,loss 2.2360873222351074
step 70/100,loss 2.3083763122558594
step 80/100,loss 2.368462562561035
step 90/100,loss 2.429439067840576
step 100/100,loss 2.4737391471862793
step 10/100,loss 1.5831407308578491
step 20/100,loss 1.8222655057907104
step 30/100,loss 1.9836606979370117
step 40/100,loss 2.089505672454834
step 50/100,loss 2.18733549118042
step 60/100,loss 2.275851011276245
step 70/100,loss 2.3295247554779053
step 80/100,loss 2.406217336654663
step 90/100,loss 2.4625091552734375
step 100/100,loss 2.512716054916382
step 10/100,loss 1.5476057529449463
step 20/100,loss 1.8073458671569824
step 30/100,loss 1.965522289276123
step 40/100,loss 2.0958902835845947
step 50/100,loss 2.1832175254821777
step 60/100,loss 2.282517671585083
step 70/100,loss 2.3572096824645996
step 80/100,loss 2.4211323261260986
step 90/100,loss 2.491734504699707
step 100/100,loss 2.5412847995758057
step 10/100,loss 1.5394271612167358
step 20/100,loss 1.8221709728240967
step 30/100,loss 1.9855037927627563
step 40/100,loss 2.121405839920044
step 50/100,loss 2.237565755844116
step 60/100,loss 2.333864450454712
step 70/100,loss 2.4077095985412598
step 80/100,loss 2.491513967514038
step 90/100,loss 2.5552725791931152
step 100/100,loss 2.6029067039489746
1083.071308851242
In [14]:
show_image(normalize_image(img))

优化2(多层全通道)

  • 如果单幅图片尺寸过大,执行梯度计算所需的时间增加,为此,可以将图拆分成多个小图快计算梯度,最后将其合并起来得到最终的图片
In [1]:
import tensorflow as tf
import numpy as np
import IPython.display as display 
import PIL.Image
from tensorflow.keras.preprocessing import image
In [2]:
##定义图像移动函数
def random_roll(img,maxroll=512):
    shift=tf.random.uniform(shape=[2],minval=-maxroll,maxval=maxroll,dtype=tf.int32)
    #print(shift)
    shift_down,shife_right=shift[0],shift[1]
    #print(shift_down,shife_right)
    img_rolled=tf.roll(tf.roll(img,shife_right,axis=1),shift_down,axis=0)
    return shift_down,shife_right,img_rolled
In [3]:
##读取图片,可以设置图片的最大尺寸
def read_image(file_name,max_dim=None):
    img = PIL.Image.open(file_name)
    if max_dim:
        img.thumbnail((max_dim,max_dim))
    return np.array(img)
In [4]:
## 图像可视化
def show_image(img):
    display.display(PIL.Image.fromarray(np.array(img)))
In [5]:
## 图像标准化
def normalize_image(img):
    img = 255*(img+1.0)/2.0
    return tf.cast(img,tf.uint8)
In [6]:
original_img=read_image("IMG_20170713_091522.jpg",max_dim=550)
In [7]:
shift_down,shife_right,img_rolled=random_roll(np.array(original_img))
show_image(img_rolled)
In [8]:
##构建模型,tf.keras.applications包括许多预训练好的模型,我们用InceptionV3模型。去掉顶层,这样可以接受新的训练数据的shape
base_model = tf.keras.applications.InceptionV3(include_top=False,weights="imagenet")
In [9]:
#选择需要优化的层
layer_name=["mixed3","mixed5"]
layers = [base_model.get_layer(name).output for name in layer_name]
In [10]:
dream_model = tf.keras.Model(inputs=base_model.input,outputs=layers)
In [11]:
##计算损失,与单个通道相差就在于计算loss.
def calc_loss(img,model):
    #channel =[13,19]#不能超过320,因为<tf.Tensor 'conv2d_85/Identity:0' shape=(None, None, None, 320) dtype=float32>,最多320个通道
    #由(300,300,3)变为(1,300,300,3)
    #因为是全通道,所以不需要选择通道了
    img=tf.expand_dims(img,axis=0)
    layer_activations=model(img)
    
    losses=[]
    for act in layer_activations:
        loss = tf.math.reduce_mean(act)##要使loss越来越大
        losses.append(loss)
    
    return tf.reduce_sum(losses)  

定义分块计算的梯度函数

In [12]:
def get_tiled_gradients(model,img,tile_size=150):
    shift_down,shife_right,img_rolled=random_roll(img,tile_size)
    gradients=tf.zeros_like(img_rolled)##初始化梯度
    
    xs=tf.range(0,img_rolled.shape[0],tile_size)
    ys=tf.range(0,img_rolled.shape[1],tile_size)
    for x in xs:
        for y in ys:
            with tf.GradientTape() as tape:
                tape.watch(img_rolled)
                img_tile=img_rolled[x:x+tile_size,y:y+tile_size]#从图像中提取该图块
                loss=calc_loss(img_tile,model)
                
                gradients=gradients+tape.gradient(loss,img_rolled)##更新梯度
    gradients=tf.roll(tf.roll(gradients,-shife_right,axis=1),-shift_down,axis=0)##将图块放回到原来的位置
    #归一化梯度值
    gradients /= tf.math.reduce_std(gradients)+1e-8
    return gradients
In [13]:
## 图像优化过程
def render_deepdream_with_octaves(model,img,steps_per_octave=100,step_size=0.01,octaves=range(-2,3),Scale=1.3):
    initial_shape=img.shape[:-1]
    
    for each in octaves:
        new_size=tf.cast(tf.convert_to_tensor(initial_shape),tf.float32)*(Scale**each)
        img=tf.image.resize(img,tf.cast(new_size,tf.int32))
        
        for step in tf.range(steps_per_octave):
            gradients=get_tiled_gradients(model,img)
            img=img+gradients*step_size
            img=tf.clip_by_value(img,-1,1)#让输出在-1,+1之间
        
    img = tf.image.resize(img,initial_shape)
    result=normalize_image(img)
    return result
In [14]:
import time
star = time.time()
#图片预处理
img = tf.keras.applications.inception_v3.preprocess_input(original_img)
img = tf.convert_to_tensor(img)
img=render_deepdream_with_octaves(dream_model,img)
print(time.time()-star)
1677.9105861186981
In [15]:
show_image(img)

耗时较长

In [11]:
##保存图片
def save_image(img,file_name):
    PIL.Image.fromarray(np.array(img)).save(file_name)
In [12]:
save_image(img,"new.jpg")